package edu.ccut.saturn.component.loader;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.Element;
import org.osgi.framework.Bundle;

import edu.ccut.saturn.component.ComponentFactory;
import edu.ccut.saturn.component.IDataInfo;
import edu.ccut.saturn.component.ILogger;
import edu.ccut.saturn.component.ISaturnDataSqlInfo;
import edu.ccut.saturn.component.IValidateUseInfo;
import edu.ccut.saturn.component.SaturnComponentException;
import edu.ccut.saturn.component.SaturnLoggerManager;
import edu.ccut.saturn.component.impl.SaturnDataInfo;
import edu.ccut.saturn.component.impl.SaturnDataItem;
import edu.ccut.saturn.component.loader.data.SqlLoader;
import edu.ccut.saturn.component.xml.Dom4jUtils;

/**
 * 数据项配置文件的加载类，加载后生成类型<code>IDataInfo</code>的实例。
 * 
 * @author 温建
 * 
 * @version 1.0 2008.9.03
 * 
 * @see IDataInfo
 * 
 */
public class SaturnDataLoader {

	private static final String LOGGER_KEY_LOAD_BUNDLE = SaturnLoggerManager.LOGGER_KEY_LOAD_BUNDLE;

	protected static ILogger logger = SaturnLoggerManager.getInstance()
			.getSaturnLogger(LOGGER_KEY_LOAD_BUNDLE);

	public static final String KEY_DATA_CONNECTIONNAME = "connectname";

	public static final String KEY_DATA_DESCRIPTION = "description";

	public static final String KEY_SQLDATA_SQLSTR = "sqlstr";

	public static final String KEY_DATA_FIELD_TYPE = "type";

	public static final String KEY_DATA_FIELD_NAME = "name";

	public static final String KEY_DATA_FIELD_COLUMN = "column";

	public static final String KEY_DATA_FIELD_SHOWNAME = "showName";

	public static final String KEY_SATURNDATA_COLUMNALIAS = "columnAlias";

	public static final String KEY_SATURNDATA_ISPRIMARYKEY = "isPrimaryKey";

	public static final String KEY_SATURNDATA_SEQUENCENAME = "sequenceName";

	public static final String KEY_DATA_FIELD_DEFAULTVALUE = "defaultValue";

	public static final String KEY_DATA_FIELD_DICTTYPEID = "dictTypeId";

	public static final String KEY_DATA_FIELD_NUMBER_FORMAT = "numberFormat";

	public static final String KEY_DATA_FIELD_DATETIME_FORMAT = "datetimeFormat";

	public static final String KEY_DATA_FIELD_LENGTH = "length";

	public static final String KEY_DATA_FIELD_JAVATYPE = "javaType";

	public static final String KEY_SATURNDATA_TABLENAME = "tableName";

	public static final String KEY_SATURNDATA_DATA = "data";

	public static final String KEY_DATA_NAME = "name";

	public static final String KEY_DATA_NAMESPACE = "namespace";

	public static final String KEY_SATURNDATA_FIELDS = "fields";

	public static final String KEY_SATURNDATA_FIELDS_FIELD = "field";

	public static final String KEY_DATA_FIELD_VALIDATES = "validates";

	public static final String KEY_SATURNDATA_SQLS = "sqls";

	public static final String KEY_DATA_DBTYPE = "dbType";

	/**
	 * 加载数据项配置文件。
	 * 
	 * @param bundle
	 * @param filePath
	 * @return
	 * @throws SaturnComponentException
	 */
	public static IDataInfo loadDataInfo(Bundle bundle, String filePath)
			throws SaturnComponentException {

		InputStream in = null;

		try {
			URL url = bundle.getEntry(filePath);
			logger.debug("START LOAD SATURNDATA : \"" + url + "\"");
			in = url.openStream();
			return loadDataInfo(bundle, in);

		} catch (IOException e) {
			logger.error(
					"Found IOException! load data file failed in bundle [key="
							+ bundle.getSymbolicName() + "], file name ["
							+ filePath + "]", e);

			throw new SaturnComponentException(
					"load data file failed in bundle [key="
							+ bundle.getSymbolicName() + "], file name ["
							+ filePath + "]", e);

		} catch (Exception e) {
			throw new SaturnComponentException(
					"load file failed in bundle[key="
							+ bundle.getSymbolicName() + "] with file name ["
							+ filePath + "]", e);

		} finally {

			try {

				if (in != null) {
					in.close();
				}

			} catch (IOException e) {
				logger.error("file input stream close error!", e);
			}
			logger.debug("END LOAD SATURNDATA");
			logger.debug("");
		}
	}

	/**
	 * 加载数据项配置文件。
	 * 
	 * @param bundle
	 * @param in
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static IDataInfo loadDataInfo(Bundle bundle, InputStream in)
			throws Exception {

		Document document = Dom4jUtils.getDocment(in);
		Element root = document.getRootElement();
		Element element = root.element(KEY_SATURNDATA_DATA);
		Element fieldsElement = element.element(KEY_SATURNDATA_FIELDS);
		String nameSpace = element.attributeValue(KEY_DATA_NAMESPACE).trim();
		String name = element.attributeValue(KEY_DATA_NAME).trim();
		String connectName = element.elementTextTrim(KEY_DATA_CONNECTIONNAME);
		String description = element.elementTextTrim(KEY_DATA_DESCRIPTION);
		String sqlStr = element.elementTextTrim(KEY_SQLDATA_SQLSTR);
		String dbType = element.attributeValue(KEY_DATA_DBTYPE);

		SaturnDataInfo saturnDataInfo = new SaturnDataInfo(connectName, sqlStr,
				description, nameSpace, name, dbType);

		loadDataItems(saturnDataInfo, fieldsElement, bundle);
		Element sqlsElement = root.element(KEY_SATURNDATA_SQLS);

		if (sqlsElement != null) {
			Map<String, ISaturnDataSqlInfo> sqlMap = SqlLoader
					.getSqlMap(sqlsElement);

			saturnDataInfo.addSqlInfosByMap(sqlMap);
		}
		return saturnDataInfo;
	}

	/**
	 * 加载数据项的字段信息。数据项分两种类型sqldata和saturndata，他们的字段描述有所不同，但使用这个方法统一加载。
	 * 
	 * @param saturnDataInfo
	 * @param fieldsElement
	 * @param bundle
	 * @throws ClassNotFoundException
	 */
	@SuppressWarnings("unchecked")
	private static void loadDataItems(IDataInfo saturnDataInfo,
			Element fieldsElement, Bundle bundle) throws ClassNotFoundException {

		List<Element> fieldElements = fieldsElement
				.elements(KEY_SATURNDATA_FIELDS_FIELD);

		for (Element fieldElement : fieldElements) {
			String name = fieldElement.attributeValue(KEY_DATA_FIELD_NAME);
			if (name != null) {
				name = name.trim();
			}

			String type = fieldElement.attributeValue(KEY_DATA_FIELD_TYPE);
			if (type != null) {
				type = type.trim();
			}

			String column = fieldElement.attributeValue(KEY_DATA_FIELD_COLUMN);
			if (column != null) {
				column = column.trim();
			}

			String columnAlias = fieldElement
					.attributeValue(KEY_SATURNDATA_COLUMNALIAS);

			if (columnAlias != null) {
				columnAlias = columnAlias.trim();
			}

			String length = fieldElement.attributeValue(KEY_DATA_FIELD_LENGTH);

			if (length != null) {
				length = length.trim();
			}

			String isPrimaryKey = fieldElement
					.attributeValue(KEY_SATURNDATA_ISPRIMARYKEY);

			if (isPrimaryKey != null) {
				isPrimaryKey = isPrimaryKey.trim();
			}

			String showName = fieldElement.attributeValue(
					KEY_DATA_FIELD_SHOWNAME);
			if(showName!=null){
				showName= showName.trim();
			}

			String javaType = fieldElement.attributeValue(
					KEY_DATA_FIELD_JAVATYPE);
			if(javaType!=null){
				javaType = javaType.trim();
			}

			String tableName = fieldElement
					.attributeValue(KEY_SATURNDATA_TABLENAME);

			if ("".equals(tableName)) {
				tableName = null;
			}

			String dictTypeId = fieldElement
					.attributeValue(KEY_DATA_FIELD_DICTTYPEID);

			if (dictTypeId != null) {
				dictTypeId = dictTypeId.trim();
			}

			String defaultValue = fieldElement
					.attributeValue(KEY_DATA_FIELD_DEFAULTVALUE);

			if (defaultValue != null) {
				defaultValue = defaultValue.trim();
			}

			String sequenceName = fieldElement
					.attributeValue(KEY_SATURNDATA_SEQUENCENAME);

			if (sequenceName != null) {
				sequenceName = sequenceName.trim();
			}

			String numberFormat = fieldElement
					.attributeValue(KEY_DATA_FIELD_NUMBER_FORMAT);

			if (numberFormat != null) {
				numberFormat = numberFormat.trim();
			}

			String datetimeFormat = fieldElement
					.attributeValue(KEY_DATA_FIELD_DATETIME_FORMAT);

			if (datetimeFormat != null) {
				datetimeFormat = datetimeFormat.trim();
			}

			Element validatesNode = fieldElement
					.element(KEY_DATA_FIELD_VALIDATES);

			IValidateUseInfo validateUseInfo = ComponentFactory
					.getValidateUseInfo(bundle, validatesNode);

			SaturnDataItem dataItem = new SaturnDataItem();
			dataItem.setColumn(column);
			dataItem.setColumnAlias(columnAlias);
			dataItem.setIsPrimaryKey(isPrimaryKey);
			dataItem.setJavaType(javaType);
			dataItem.setName(name);
			dataItem.setSequenceName(sequenceName);
			dataItem.setTableName(tableName);
			dataItem.setType(type);
			dataItem.setDefaultValue(defaultValue);
			dataItem.setDictTypeId(dictTypeId);
			dataItem.setValidateUseInfo(validateUseInfo);
			dataItem.setShowName(showName);
			dataItem.setLength(length);
			dataItem.setNumberFormat(numberFormat);
			dataItem.setDatetimeFormat(datetimeFormat);
			saturnDataInfo.addDataItem(dataItem);
		}
	}
}

